__author__ = 'aaqqxx'
# -*- coding: utf-8 -*-
#!/usr/bin/env python
"""
The file is to plot one file or 2 files or 3 files or 4 files, the data in file split with whitespace.

The default uinit of y1 or y2 is counts or counts/s, and the unit of x is ms.
The x_fator should be change to the sampling time.
The y_unit should be change to the actual unit with the y_factor.

Maybe need more interface to improve the feture.More sys.argv[3], sys.argv[4] to
change the unit and factors.

"""

import sys
import numpy as np
import numpy
from matplotlib.pylab import plot
from pylab import show,axes,savetxt
import matplotlib.pyplot as plt
import time
from os.path import getctime
from matplotlib.widgets import Button

data1_to_save = [] # the list to contain the data1
data2_to_save = [] # the list to contain the data2
data3_to_save = [] # the list to contain the data3
data4_to_save = [] # the list to contain the data4

#used in position step move tuning

def is_all_between(data,smallest,biggest):
    for each in data:
        if each >=smallest and each<=biggest:
            value = True
        else:
            value = False
            break
    return value

def get_setting_time(data,cmd_position,time_tick = 1,time_unit = 'ms',setting_time_factor = 0.05,is_cal_all = True):
    setting_time = -1
    biggest = cmd_position*(1+setting_time_factor)
    smallest = cmd_position*(1-setting_time_factor)
    if is_cal_all:
        for i,each in enumerate(data):
            if (data[i]>= smallest and data[i] <= biggest): #record the first point according to the condition
                if is_all_between(data[i:],smallest,biggest):
                    setting_time = i
                    break
            else :
                setting_time = -1
    else:
        data = data[:len(data)/2]
        for i,each in enumerate(data): #only use the half of the data to calculate the setting_time.
            if (data[i]>= smallest and data[i] <= biggest):#record the first point according to the condition
                if is_all_between(data[i:],smallest,biggest):
                    setting_time = i
                    break
            else :
                setting_time = -1
    return setting_time

def get_raise_time(data, cmd_position,time_tick = 1, time_unit="ms",raise_time_factor = 0.7):
    if time_unit == "ms":   #if time_unit is "ms",the time_factor
        time_tick = 1
    for i,each in enumerate(data):
        if (data[i] >= cmd_position*raise_time_factor):
            raise_time= i*time_tick
            break
        else :
            raise_time = -1
    return raise_time

def get_peak_time(data,cmd_position):
    if time_unit == "ms":   #if time_unit is "ms",the time_factor
        time_tick = 1
    for i,each in enumerate(data):
        if (data[i] >= cmd_position*raise_time_factor):
            raise_time= i*time_tick
            break
        else :
            raise_time = -1

def plot_a(filename='./D_M1_cmd_pos1.txt'):
    from matplotlib.pylab import plotfile
    from pylab import show
    plotfile(filename)
    show()

#def plot_two(position_data,position_tick,veloctiy_data,velocity_tick):


def get_ylabel(filename1,y_unit='cts'):
    if 'av' in filename1:
        ylabel = 'Actual_velocity('+ y_unit + '/s)'
    elif 'cv' in filename1:
        ylabel = 'Command velocity('+ y_unit +'/s)'
    elif 'cp' in filename1:
        ylabel = 'Command position('+ y_unit+ ')'
    elif 'ap' in filename1:
        ylabel =  'Actual position(' + y_unit +')'
    elif 'fe' in filename1:
        ylabel = 'following error(' + y_unit +')'
    else:
        ylabel = ''
    return ylabel

def plot_one(filename,y_factor=1,x_factor=1,y_unit='counts',x_unit='ms',unit_motor='DOE.motor1',**otheroption):#date
    ylabel = get_ylabel(filename,y_unit)
    xlabel = 'time('+x_unit+')'
    y=[]
    raw_y = open(filename).readline().split()
    for each in raw_y:
        y.append(float(each))
    y = numpy.multiply(y,y_factor)#get the real yvalue after multiply a factor

    executed_time = time.strftime('%a, %d %b %Y %H:%M:%S ',time.gmtime(getctime(filename)))#a little wrong?
    x = numpy.arange(0,len(y),1*x_factor)#get the real xvalue after multiply a factors
    fig = plt.figure('name','hello')
    axis = fig.add_subplot(111)
    line = axis.plot(x,y,label=filename[-1:-7])
    axis.set_ylabel(ylabel)
    axis.set_xlabel(xlabel)
    motor_name = filename[:-12]
    axis.set_title(motor_name+' motion executed at '+executed_time)
    axis.legend((line,),(ylabel,))
    plt.show()

def get_freq_amp_of_data_by_fft(data,sample_period=0.001*300/173,number_of_fft=1024,time_unit='s'):
    """
    计算data的FFT，返回数据对应的频率和幅值
    """
    #时间换算为以s为单位
    if time_unit == 'us':
        sample_period = sample_period/1000000.
    if time_unit=='ms':
        sample_period=sample_period/1000.
    elif time_unit=='s':
        sample_period=sample_period

    if len(data)==0:
        return [],[]
    tmp = []#用来装转化后的数据
    for each in data:
        tmp.append(float(each))#确保转换为浮点型
#    number_of_fft = len(data)
#    fs = 1/sample_period  # 采样频率
#    y = np.fft.fft(f1)#len(x)为600，len(y)为1024
#    n = np.arange(0,len(y))
#    f = fs*n/len(y)
#    y = np.abs(y)
#    y[1:-1] = np.multiply(y[1:-1],2./len(y))#非直流分量的幅值为abs()/(1/2的采样数)
#    y[0] = y[0]/len(y)#直流分量的幅值为abs()/(采样数)

#计算FFT,得到一组复数
    data_after_fft = np.fft.fft(tmp,number_of_fft)#f1为信号数据，number_of_fft为FFT采样取样点数

#计算得到个点FFT对应的频率，
    time_step = sample_period
    freq = np.fft.fftfreq(len(data_after_fft),d=time_step)

#计算各频率点上的幅值大小
    amp = np.abs(data_after_fft)
    amp[1:-1] = np.multiply(amp[1:-1],2./len(data))#非直流分量的幅值为abs()/(1/2的采样数)
    amp[0] = amp[0]/len(data)#直流分量的幅值为abs()/(采样数)

#返回数据对应的频率和幅值
    return  freq,amp


def file_plot_fft(filename1, filename2,dt = 0.0002,dt_unit = 's'):

    data1 = open(filename1).readline().split()
    data2 = open(filename2).readline().split()
    f1 = []
    f2 = []
    for each in data1:
        f1.append(float(each))

    for each1 in data2:
        f2.append(float(each1))

    t = np.arange(0,len(f1)*dt,dt)
    fourier_transform_f1 = np.fft.fft(f1)/len(f1)
    fourier_transform_f2 = np.fft.fft(f2)/len(f2)
    spectrum_f1 = np.abs(fourier_transform_f1)
    spectrum_f2 = np.abs(fourier_transform_f2)
    freq1 = np.fft.fftfreq(t.shape[-1], d = dt)
    freq2 = np.fft.fftfreq(t.shape[-1], d = dt)
    #freq1 = np.fft.fftshift(freq1)
    #freq2 = np.fft.fftshift(freq2)
    plt.semilogy(freq1[:len(f1)/2],spectrum_f1[:len(f1)/2])
    plt.semilogy(freq2[:len(f1)/2],spectrum_f2[:len(f1)/2])
    plt.show()


def calc_fft(data1, data2, data3, data4, dt = 0.0004274,dt_unit = 's'):

    """
    下面的基本有用，使用单个的来
    freq1 = np.fft.fftfreq(t.shape[-1], d = dt)
    freq2 = np.fft.fftfreq(t.shape[-1], d = dt)
    freq3 = np.fft.fftfreq(t.shape[-1], d = dt)
    #freq1 = np.fft.fftshift(freq1)
    #freq2 = np.fft.fftshift(freq2)
    """

    freq1,spectrum_f1 = get_freq_amp_of_data_by_fft(data1,sample_period=dt,time_unit=dt_unit)
    freq2,spectrum_f2 = get_freq_amp_of_data_by_fft(data2,sample_period=dt,time_unit=dt_unit)
    freq3,spectrum_f3 = get_freq_amp_of_data_by_fft(data3,sample_period=dt,time_unit=dt_unit)
    freq4,spectrum_f4 = get_freq_amp_of_data_by_fft(data4,sample_period=dt,time_unit=dt_unit)

    return freq1,spectrum_f1,freq2,spectrum_f2,freq3,spectrum_f3,freq4,spectrum_f4


#def savedata1(filename):#Maybe don't use? event? or "savedata1(filename,data)"
#    filename = sys.argv[1]+time.ctime()
#    savetxt(filename,data1_to_save)

#def savedata2(filename):
#    filename = sys.argv[2]+time.ctime()
#    savetxt(filename,data2_to_save)

def get_data_from_file(filename):
    """
    文件名要求：符合02下位机保存的文件名例如T_P0_M1_ap_step_0.txt。
    文件格式要求：纯数据而且以空格为分隔符。
    输入文件名，返回文件中的数据到数组中
    """
    data=[]
    if filename=="None":
        data=[]
    elif "cv" in filename:
        filename = filename[:8]+"cp"+filename[10:]
        tmp = open(filename).read().split()
        tmp1=[]
        for each in tmp:
            tmp1.append(float(each))
        data=np.diff(tmp1)
        data=np.append(data,data[-1])#
    elif 'ca' in filename:
        filename = filename[:8]+"cp"+filename[10:]
        tmp = open(filename).read().split()
        tmp1 = []
        for each in tmp:
            tmp1.append(float(each))
        data=np.diff(tmp1,2)
        data=np.append(data,data[-2:])#
    elif 'aa' in filename:
        filename = filename[:8]+'ap'+filename[10:]
        tmp = open(filename).read().split()
        tmp1=[]
        for each in tmp:
            tmp1.append(float(each))
        data=np.diff(tmp1,2)
        data=np.append(data,data[-2:])#
    else:
        tmp=open(filename).read().split()
        for each in tmp:
            data.append(float(each))
    return data

def get_key_from_filename(filename):
    """
    输入文件名得到cp,ap,cv,av,ca,aa,fe,None等键，用于字典存放数据
    """
    import re
    key='T_P[0-7]_M[1-8]_([acf][pvae])_'
    m=re.match(key,filename)
    if m is not None:
        print 'm.group(1) is:',m.group(1)
        return m.group(1)
    elif filename == 'None':
        return 'None'
    
def get_data_from_all_key_list_and_filename_list(key_list,filename_list,data_all):
    """
    4个不同的数据～～
    输入：键值列表，需要绘制的文件（数据名称）列表，所有数据所在的字典。
    返回：一个列表，里面有4个不同的数据列表
    """
    i=0
    line_data=[[],[],[],[]]
    for key in key_list:
        print key,"~~~~"
        for each in filename_list:
            if each!='None':
                if key in each:
                    print i,key,each
                    line_data[i]=data_all[key]
                    i=i+1
                    break
            elif each =='None':
                if key in each:
                    line_data[i]=data_all[key]
                    i=i+1
                    break
    return line_data


def plot_all(filename_list,data_gather_period=0.000402,mode="step",left_axis='Position',right_axis='Fellowing_Error',pid_para='Ixx30=10000',
             data_gather_period_time_unit='us',
             y1_unit='cts',
             y2_unit='cts',
             y3_unit='cts',
             y4_unit='cts',
             x1_unit='ms',
             x1_factor=1,
             x2_factor=1,
             x3_factor=1,
             x4_factor=1):
    """
    用于绘制4个数据文件的图形，根据不能的mode显示不同的提示信息，根据left_axis和right_axis显示不同的legend.
    len(filename_list)为4,文件的格式为纯数据,以空格为分隔符。
    数据采样时间间隔为0.000402s,可以用来进行FFT变换
    模式为对单元就是"unit"，对调试就是"step","ramp","para","trap"
    left_axis为左边Y轴的单位。
    right_axis为右边Y周的单位。
    pid_para为当前的PID参数
    y1_unit,y2_unit,y3_unit,y4_unit为主要的数据的长度单位：cts,mm,度,
    x1_factor,x2_factor,x3_factor,x4_factor为长度的比例因子,可以在以后用来进行坐标单位变换,
    """
    global data1_to_save
    global data2_to_save
    global data3_to_save
    global data4_to_save

    #初始化字典，用于存放不同类型的数据。
    #ap:actual position,cp:command position
    #cv:command velocity,av:actual velocity
    #ca:command acc,aa:actual acc
    #fe:fellowing error
    #None:无数据
    data_all={}.fromkeys(('ap','cp','av','cv','ca','aa','fe','None'),0)
    #~~~~~~~~将本次运动采集的所有数据都读取进来~~~~~~~~~
    for key in data_all:
        for each_file in filename_list:
            if key in each_file:
                data_all[key]=get_data_from_file(each_file)
                break
    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
    
    #~~~~~~~~根据需要绘制的文件名，得到相应的key，用于字典存放数据
    
    key_list_for_plot=[]
    for each in filename_list:
        key_list_for_plot.append(get_key_from_filename(each))

    line_data=get_data_from_all_key_list_and_filename_list(key_list_for_plot,filename_list,data_all)

    class Index:
        ind = 0
        def fft(self, event):
            self.ind += 1
            freq1,spectrum_f1,freq2,spectrum_f2,freq3,spectrum_f3,freq4,spectrum_f4=calc_fft(line_data[0],line_data[1],line_data[2],line_data[3],dt=float(data_gather_period),dt_unit='us')

            ax1.clear()
            ax2.clear()

            ax1.set_yscale('log')
            ax2.set_yscale('log')
            ax1.xaxis.grid(True, which='major')
            ax1.xaxis.grid(True, which='minor')

            line1 = ax1.plot(freq1[:len(spectrum_f1)/2],spectrum_f1[:len(spectrum_f1)/2],color = 'b')
            line2 = ax1.plot(freq2[:len(spectrum_f2)/2],spectrum_f2[:len(spectrum_f2)/2],color = 'g')
            line3 = ax2.plot(freq3[:len(spectrum_f3)/2],spectrum_f3[:len(spectrum_f3)/2],color = 'r',)
            line4 = ax2.plot(freq4[:len(spectrum_f4)/2],spectrum_f4[:len(spectrum_f4)/2],color = 'brown')

            ax1.set_title(motor_name+' motion executed at '+executed_time)
            ax1.set_ylabel(y2_ylabel,color='g')
            ax1.set_xlabel('freq(Hz)')

            ax2.set_ylabel(y3_ylabel,color='r')
            ax2.yaxis.tick_right()
            ax2.yaxis.set_label_position('right')
            for tl in ax2.get_yticklabels():
                tl.set_color('r')
            ax1.grid(True)
            #ax1.set_ylim(ymin=-10)

            ax1.legend((line1,line2,line3,line4),(y1_ylabel,y2_ylabel,y3_ylabel,y4_ylabel),loc='best')#get_freq_amp_of_data_by_fft

            if (mode=='step'):
                cmd_position = max(data_all['cp'])
                raise_time = str(get_raise_time(data_all['ap'],cmd_position))
                setting_time = str(get_setting_time(data_all['ap'][:len(data_all['ap'])/4],cmd_position))
                str_annotate = 'raise time=' + raise_time + x1_unit+"     the setting time="+ setting_time + x1_unit
                ax1.annotate(str_annotate, xy=(0.2, 0),  xycoords='figure fraction',
                    xytext=(20, 20), textcoords='offset points',
                    ha="left", va="bottom",
                )

            #plt.axis([0,1000,0,max(spectrum_f1)])
            plt.draw()

        def normal(self, event):
            self.ind -= 1
            ax1.clear()
            ax2.clear()
            line1 = ax1.plot(np.multiply(x1_factor,np.arange(0,len(line_data[0]))),line_data[0], color = 'b')
            line2 = ax1.plot(np.multiply(x1_factor,np.arange(0,len(line_data[1]))),line_data[1], color = 'g')
            line3 = ax2.plot(np.multiply(x1_factor,np.arange(0,len(line_data[2]))),line_data[2], color = 'r')
            line4 = ax2.plot(np.multiply(x1_factor,np.arange(0,len(line_data[3]))),line_data[3], color = 'brown')
            ax1.set_title(motor_name+' motion executed at '+executed_time)
            ax1.set_ylabel(y2_ylabel,color='g')
            ax1.set_xlabel('time(ms)')
            ax2.set_ylabel(y3_ylabel,color='r')
            #plt.axis([0,len(y1),y1.min(),y1.max()])

            ax2.yaxis.tick_right()
            ax2.yaxis.set_label_position('right')
            for each in [line_data[2],line_data[3]]:
                if len(line_data[2]):
                    for tl in ax2.get_yticklabels():
                        tl.set_color('r')
                if len(line_data[3]):
                    for tl in ax2.get_yticklabels():
                        tl.set_color('brown')

            ax1.legend((line1,line2,line3,line4),(y1_ylabel,y2_ylabel,y3_ylabel,y4_ylabel))

            if (mode=='step'):
                cmd_position = max(data_all['cp'])
                raise_time = str(get_raise_time(data_all['ap'],cmd_position))
                setting_time = str(get_setting_time(data_all['ap'][:len(data_all['ap'])/4],cmd_position))
                str_annotate = 'raise time=' + raise_time + x1_unit+"     the setting time="+ setting_time + x1_unit
                ax1.annotate(str_annotate, xy=(0.2, 0),  xycoords='figure fraction',
                    xytext=(20, 20), textcoords='offset points',
                    ha="left", va="bottom",
                )
            ax1.grid(True)
            plt.draw()

    fig = plt.figure()
    ax1 = fig.add_subplot(111)

    y1_ylabel = get_ylabel(filename[0],y1_unit)
    y2_ylabel = get_ylabel(filename[1],y2_unit)
    y3_ylabel = get_ylabel(filename[2],y3_unit)
    y4_ylabel = get_ylabel(filename[3],y4_unit)

    #get line1以及起相关属性
    # #!!!!!!!!!!!!!时间计算有问题,有时候除以1000会出错＝。＝！
    #!!!!!!!!!!!data_gather_period=300/174.*1000#应该算是经验值，感觉是这多ms一个采样点。。。。。待查。。。
    if data_gather_period_time_unit =='us' and x1_unit=='ms':

        x1_factor = float(data_gather_period)/1000.
        print "x11_factor is:",x1_factor

    x1 = numpy.arange(0,len(line_data[0])*x1_factor,x1_factor)#get the real xvalue after multiply a factors
    #x11 =numpy.arange(0,len(line_data[0])*x11_factor,x11_factor)
    print "len(x1),len(line_data[0]) is:",len(x1),len(line_data[0])


    line1=ax1.plot(x1,line_data[0],'b')
    ax1.set_xlabel('time(ms)')
    # Make the y-axis label and tick labels match the line color.
    ax1.set_ylabel(y1_ylabel,color='b')
    for tl in ax1.get_yticklabels():
        tl.set_color('b')

    #get x2
    if data_gather_period_time_unit =='us' and x1_unit=='ms':
        x2_factor = float(data_gather_period)/1000.

    x2 = numpy.arange(0,len(line_data[1])*x2_factor,x2_factor)#get the real xvalue after multiply a factors

    line2=ax1.plot(x2, line_data[1], 'g')
    ax1.set_xlabel('time(ms)')
    ax1.set_ylabel(y2_ylabel,color='g')
    ax2 = ax1.twinx()

    #get x3
    if data_gather_period_time_unit =='us' and x1_unit=='ms':
        x3_factor = float(data_gather_period)/1000.
    x3 = numpy.arange(0,len(line_data[2])*x3_factor,x3_factor)#get the real xvalue after multiply a factors
    line3=ax2.plot(x3, line_data[2], 'r')
    ax2.set_ylabel(y3_ylabel,color='r')
    for tl in ax2.get_yticklabels():
        tl.set_color('r')
    #get x4
    if data_gather_period_time_unit =='us' and x1_unit=='ms':
        x4_factor = float(data_gather_period)/1000.
    x4 = numpy.arange(0,len(line_data[3])*x4_factor,x4_factor)#get the real xvalue after multiply a factors
    line4 = ax2.plot(x4,line_data[3],'brown')
    for tl in ax2.get_yticklabels():
        tl.set_color('brown')

    callback = Index()
    axprev = plt.axes([0.7, 0.025, 0.1, 0.035])
    axnext = plt.axes([0.81, 0.025, 0.1, 0.035])
    bnext = Button(axnext, 'FFT')
    bnext.on_clicked(callback.fft)
    bprev = Button(axprev, 'normal')
    bprev.on_clicked(callback.normal)

    if mode == "step":
        raise_time = str(get_raise_time(line_data[1],cmd_position=200))
        setting_time = str(get_setting_time(line_data[1][:len(line_data[1])/4],cmd_position=200))
        str_annotate = 'raise time=' + raise_time + x1_unit+"     the setting time="+ setting_time + x1_unit

        ax1.annotate(str_annotate, xy=(0.2, 0),  xycoords='figure fraction',
            xytext=(20, 20), textcoords='offset points',
            ha="left", va="bottom",
        )

    '''
    tmplist=['ap','cp','av','fe']#只有文件名含有'ap','cp','av','fe'的文件才是真的文件有时间。
    for each in tmplist:
        #if each !="None":
        for each1 in filename_list:
            if each in each1:
                print "each and each 1 is :",each,each1
                executed_time = time.strftime('%a, %d %b %Y %H:%M:%S ',time.gmtime(getctime(each1)))
                break
            else:
                executed_time = "Unkown"
                #executed_time = '22'

    '''
    for each2 in filename_list:
        if len(each2)!=4:
            filename_have_time=each2[:8]+'cp'+each2[10:]
    executed_time=time.strftime('%a, %d %b %Y %H:%M:%S ',time.gmtime(getctime(filename_have_time)))

    motor_name = filename[1][:-12]
    ax1.set_title(motor_name+' motion executed at '+executed_time)


    ax1.legend((line1,line2,line3,line4),(y1_ylabel,y2_ylabel,y3_ylabel,y4_ylabel))
    data1_to_save = line_data[0]
    data2_to_save = line_data[1]
    data3_to_save = line_data[2]
    data4_to_save = line_data[3]
    #  resetax1 = axes([0.7, 0.01, 0.05, 0.075])
    #  button1 = Button(resetax1, 'Save_y1')
    #  button1.on_clicked(savedata1)
    #  resetax2 = axes([0.85, 0.01, 0.05, 0.075])
    #  button2 = Button(resetax2, 'Save_y2')
    #  button2.on_clicked(savedata2)
    ax1.grid(True)
    plt.show()

if __name__ == "__main__":
    print "the length of argv is: ",len(sys.argv)
    if len(sys.argv)==2 :
        plot_one(sys.argv[1])
    if len(sys.argv)==5:
        filename=sys.argv[1:5]
        plot_all(filename,sys.argv[5])
    if len(sys.argv)==6:
        filename=sys.argv[1:5]
        plot_all(filename,sys.argv[5])
    if len(sys.argv)==9:
        filename=sys.argv[1:5]
        print filename
        plot_all(filename,sys.argv[5],sys.argv[6],sys.argv[7],sys.argv[8])

"""
	filename = sys.argv[1]
	filename_context = open(filename).readline().split()#split() change the type of string into a list type split with whitespace.
	filename_context_len = len(filename_context)
	pos_time_axis = numpy.arange(0,filename_context_len,1)

	filename_vel = sys.argv[2]
	filename_context_vel = open(filename_vel).readline().split()#split() change the type of string into a list type split with whitespace.
	vel_time_axis = numpy.arange(0,len(filename_context_vel),1)

	plot(pos_time_axis,filename_context,'r',vel_time_axis,filename_context_vel,'b')
	show()
"""
